home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / cool / ge_cool.lha / GE_COOL2.1 / src / Rational / Rational.C < prev    next >
C/C++ Source or Header  |  1992-05-08  |  12KB  |  351 lines

  1. //
  2. // Copyright (C) 1991 Texas Instruments Incorporated.
  3. //
  4. // Permission is granted to any individual or institution to use, copy, modify,
  5. // and distribute this software, provided that this complete copyright and
  6. // permission notice is maintained, intact, in all copies and supporting
  7. // documentation.
  8. //
  9. // Texas Instruments Incorporated provides this software "as is" without
  10. // express or implied warranty.
  11. //
  12. //
  13. // Created: MBN 10/31/89 -- Initial design and implementation
  14. // Updated: MBN 03/04/90 -- Added execption for DIVIDE_BY_ZERO
  15. // Updated: MJF 03/12/90 -- Added group names to RAISE
  16. // Updated: MJF 07/31/90 -- Added terse print
  17. // Updated: DLS 04/01/91 -- New lite version
  18. //
  19. // The CoolRational class  implements rational numbers  and arithmetic.  A CoolRational
  20. // object has the same precision and range of values as the built-in type long.
  21. // Implicit conversion to the system defined types short, int, long, float, and
  22. // double is supported by  overloaded  operator member functions.  Although the
  23. // CoolRational class makes judicous use  of inline  functions and  deals only with
  24. // integral values, the user  is warned that  the CoolRational  integer  arithmetic
  25. // class is still considerably slower than the built-in  integer data types. If
  26. // the range  of values  anticipated will  fit into a  built-in  type, use that
  27. // instead.
  28. //
  29.  
  30. #ifndef RATIONAL_H                // If no CoolRational class
  31. #include <cool/Rational.h>            // Include class definition
  32. #endif
  33.  
  34. #if defined(DOS)
  35. extern "C" {
  36. #include <stdlib.h>                // For exit()
  37. }
  38. #else
  39. #include <stdlib.h>                // For exit()
  40. #endif
  41.  
  42.  
  43. // normalize -- Private function to normalize the numerator and denominator of
  44. //              a rational number
  45. // Input:       None
  46. // Output:      None
  47.  
  48. void CoolRational::normalize () {
  49.   if (this->num != 1 && this->den != 1) {    // Is there something to do?
  50.     long common = this->gcd (this->num, this->den); // Calculate GCD
  51.     if (common != 1) {                // If GCD is not one
  52.       this->num /= common;            // Calculate new numerator
  53.       this->den /= common;            // Calculate new denominator
  54.     }
  55.   }
  56.   if (this->den < 0) {                // If sign is in denominator
  57.     this->num *= -1;                // Multiply num and den by -1
  58.     this->den *= -1;                // To keep sign in numerator
  59.   }
  60.   this->state = N_OK;                // Set state to OK
  61. }
  62.  
  63.  
  64. // gcd -- calculate the GCD for two integer values
  65. // Input: Two long numbers
  66. // Output: Greatest common denominator
  67.  
  68. long CoolRational::gcd (long l1, long l2) {
  69.   long temp;
  70.   while (l2) {                    // While non-zero value
  71.     temp = l2;                    // Save current value
  72.     l2 = l1 % l2;                // Assign remainder of division
  73.     l1 = temp;                    // Copy old value
  74.   }
  75.   return l1;                    // Return GCD of numbers
  76. }
  77.  
  78.  
  79. // CoolRational -- Constructor with initial long arguments
  80. // Input:      Numerator, optional denominator
  81. // Output:     None
  82.  
  83. CoolRational::CoolRational (long n, long d) {
  84.   this->num = n;                // Set numerator
  85. #if ERROR_CHECKING                // If exception handling 
  86.   if (d == 0) {                    // Then if denominator is zero
  87.     //RAISE (Error, SYM(CoolRational), SYM(Zero_Denominator),
  88.     printf ("CoolRational::CoolRational(): Denominator of zero specified.\n");
  89.     abort ();                    // terminate in error with exit
  90.   }
  91. #endif
  92.   this->den = d;                // Set denominator
  93.   this->normalize ();                // Normalize rational
  94. }
  95.  
  96.  
  97. // operator short -- Impilict conversion operator from CoolRational to a short
  98. // Input:            None
  99. // Output:           Short value equivalent to truncated rational
  100.  
  101. CoolRational::operator short () {
  102.   long temp = this->truncate ();        // Return truncated rational
  103.   if (temp > MAXSHORT) {            // If too big for a short
  104.     this->state = N_OVERFLOW;            // Set condition state
  105.     this->overflow ("operator short()");    // Raise exception
  106.   }
  107.   if (temp < MINSHORT) {            // If too small for a short
  108.     this->state = N_UNDERFLOW;            // Set condition state
  109.     this->underflow ("operator short()");    // Raise exception
  110.   }
  111.   return (short)temp;                // Return converted value
  112. }
  113.  
  114.  
  115. // operator int -- Impilict conversion operator from CoolRational to an int
  116. // Input:          None
  117. // Output:         Int value equivalent to truncated rational
  118.  
  119. CoolRational::operator int () {
  120.   long temp = this->truncate ();        // Return truncated rational
  121.   if (temp > MAXINT) {                // If too big for an int
  122.     this->state = N_OVERFLOW;            // Set condition state
  123.     this->overflow ("operator int()");        // Raise exception
  124.   }
  125.   if (temp < MININT) {                // If too small for an int
  126.     this->state = N_UNDERFLOW;            // Set condition state
  127.     this->underflow ("operator int()");        // Raise exception
  128.   }
  129.   return (int)temp;                // Return converted value
  130. }
  131.  
  132.  
  133. // operator long -- Implicit conversion operator from CoolRational to a long
  134. // Input:           None
  135. // Output:          Long value equivalent to truncated rational
  136.  
  137. CoolRational::operator long () {
  138.   long temp = this->truncate ();        // Return truncated rational
  139.   if (temp > MAXLONG) {                // If too big for an int
  140.     this->state = N_OVERFLOW;            // Set condition state
  141.     this->overflow ("operator int()");        // Raise exception
  142.   }
  143.   if (temp < MINLONG) {                // If too small for an int
  144.     this->state = N_UNDERFLOW;            // Set condition state
  145.     this->underflow ("operator int()");        // Raise exception
  146.   }
  147.   return (long)temp;                // Return converted value
  148. }
  149.  
  150.  
  151. // operator float -- Implicit conversion operator from CoolRational to a float
  152. // Input:            None
  153. // Output:           Float value equivalent to rational
  154.  
  155. CoolRational::operator float ()
  156. {
  157.   if (this->num > MAXFLOAT || this->den > MAXFLOAT){// Out of range?
  158.     this->state = N_OVERFLOW;                // Set condition state
  159.     this->overflow ("operator float()");        // Raise exception
  160.   }
  161.   if ((this->num < 0.0 && (-this->num) < MINFLOAT) ||
  162.       (this->den < 0.0 && (-this->den) < MINFLOAT)){ // Out of ranbge?
  163.     this->state = N_UNDERFLOW;                // Set condition state
  164.     this->underflow ("operator float()");        // Raise exception
  165.   }
  166.   return ((float)this->num)/((float)this->den);        // Float answer
  167. }
  168.  
  169.  
  170. // invert -- Invert rational number
  171. // Input:    None
  172. // Output:   Reference to inverted number
  173.  
  174. CoolRational& CoolRational::invert () {
  175.   if (this->num == 0 && this->den != 0) {    // If zero numerator only
  176.     if (this->den < 0) {            // If negative denominator
  177.       this->state = N_MINUS_INFINITY;        // Set condition state
  178.       this->minus_infinity ("invert");        // And raise exception
  179.     }
  180.     else {
  181.       this->state = N_PLUS_INFINITY;        // Set condition state
  182.       this->plus_infinity ("invert");        // And raise exception
  183.     }
  184.   }
  185.   long temp = this->num;            // Save numerator
  186.   if (temp > 0) {
  187.     this->num = this->den;
  188.     this->den = temp;
  189.   } else {
  190.     this->num = this->den * -1;            // Switch denominator/numerator
  191.     this->den = temp * -1;            // And keep sign in numerator
  192.   }
  193.   return *this;                    // Return reference
  194. }
  195.  
  196.  
  197. // round -- Converts rational value by rounding to the nearest integer
  198. // Input:   None
  199. // Output:  Long
  200.  
  201. long CoolRational::round () const {
  202.   long ival = this->num / this->den;        // Calculate integer answer
  203.   if (ival > MAXDOUBLE)                // If too big
  204.     this->overflow ("operator double()");    // Raise exception
  205.   if (ival < 0 && (-ival) < MINDOUBLE)        // If out of range
  206.     this->underflow ("operator double()");    // Raise exception
  207.   double fval = ((double)this->num)/((double)this->den); // Double answer
  208.   if (ival < 0)                          // If negative
  209.     return (ival-(((-fval+ival) >= 0.5) ? 1 : 0));    // Round down if needed
  210.   else                              // Else positive, so
  211.     return (ival + (((fval - ival) >= 0.5) ? 1 : 0)); // Round up if needed
  212. }
  213.  
  214.  
  215. // operator+= -- Overload the addition with assignment operator for rational
  216. // Input:        Reference to a rational number
  217. // Output:       Mutated *this
  218.  
  219. CoolRational& CoolRational::operator+= (const CoolRational& r) {
  220.   if (this->den == r.den)            // If same denominator
  221.     this->num += r.num;                // Just add to numerator
  222.   else {
  223.     this->num = (this->num*r.den) + (this->den*r.num); // New numerator
  224.     this->den *= r.den;                       // New denominator
  225.   }
  226.   this->normalize ();                // Normalize rational
  227.   return *this;
  228. }
  229.  
  230.  
  231. // operator-= -- Overload the substraction with assignment operator for rational
  232. // Input:        Reference to a rational number
  233. // Output:       Mutated *this
  234.  
  235. CoolRational& CoolRational::operator-= (const CoolRational& r) {
  236.   if (this->den == r.den)            // If same denominator
  237.     this->num -= r.num;                // Just add to numerator
  238.   else {
  239.     this->num = (this->num*r.den) - (this->den*r.num); // New numerator
  240.     this->den *= r.den;                       // New denominator
  241.   }
  242.   this->normalize ();                // Normalize rational
  243.   return *this;
  244. }
  245.  
  246.  
  247. // operator*= -- Overload the multiply/assign operator for rational
  248. // Input:       Reference to a rational number
  249. // Output:      Reference to modified rational
  250.  
  251. CoolRational& CoolRational::operator*= (const CoolRational& r) {
  252.   this->num = this->num * r.num;        // Multiply numerators
  253.   this->den = this->den * r.den;        // Multiply denominators
  254.   this->normalize ();                // Normalize rational
  255.   return *this;                    // Return result
  256. }
  257.  
  258.  
  259. // operator/= -- Overload the divide with assignment operator for rational
  260. // Input:        Reference to a rational number
  261. // Output:       None
  262.  
  263. CoolRational& CoolRational::operator/= (const CoolRational& r) {
  264.   if (r.num == 0) {
  265.     this->state = N_DIVIDE_BY_ZERO;        // Set condition state
  266.     this->divide_by_zero ("operator/=()");
  267.   }
  268.   CoolRational temp(r);            // Create temporary work copy
  269.   return (*this *= temp.invert());
  270. }
  271.  
  272. // operator %= -- Overload the modulo with assignment operator for rational
  273. // Input:         Reference to a rational number
  274. // Output:        Mutated *this
  275.  
  276. CoolRational& CoolRational::operator%= (const CoolRational& r) {
  277.   if (this->den == r.den)            // If same denominator
  278.     this->num %= r.num;                // Just calculate modulus
  279.   else {
  280.     this->num = (this->num*r.den) % (this->den*r.num); // New numerator
  281.     this->den *= r.den;                       // New denominator
  282.   }
  283.   this->normalize ();                // Normalize rational
  284.   return *this;
  285. }
  286.  
  287. // minus_infinity -- Raise Error exception for negative infinity
  288. // Input:            Character string of derived class and function
  289. // Output:           None
  290.  
  291. void CoolRational::minus_infinity (const char* name) const {
  292.   //RAISE (Error, SYM(CoolRational), SYM(Minus_Infinity),
  293.   printf ("CoolRational::%s: Operation results in negative infinity value.\n",
  294.       name);
  295.   abort ();                    // terminate in error with exit
  296. }
  297.  
  298.  
  299. // plus_infinity -- Raise Error exception for positive infinity
  300. // Input:           Character string of derived class and function
  301. // Output:          None
  302.  
  303. void CoolRational::plus_infinity (const char* name) const {
  304.   //RAISE (Error, SYM(CoolRational), SYM(Plus_Infinity),
  305.   printf ("CoolRational::%s: Operation results in positive infinity value.\n",
  306.       name);
  307.   abort ();                    // terminate in error with exit
  308. }
  309.  
  310.  
  311. // overflow -- Raise Error exception for overflow occuring during conversion
  312. // Input:      Character string of derived class and function
  313. // Output:     None
  314.  
  315. void CoolRational::overflow (const char* name) const {
  316.   //RAISE (Error, SYM(CoolRational), SYM(Overflow),
  317.   printf ("CoolRational::%s: Overflow occured during type conversion.\n", name);
  318.   abort ();                    // terminate in error with exit
  319. }
  320.  
  321.  
  322. // underflow -- Raise Error exception for underflow occuring during conversion
  323. // Input:       Character string of derived class name and function
  324. // Output:      None
  325.  
  326. void CoolRational::underflow (const char* name) const {
  327.   //RAISE (Error, SYM(CoolRational), SYM(Underflow),
  328.   printf ("CoolRational::%s: Underflow occured during type conversion.\n", name);
  329.   abort ();                    // terminate in error with exit
  330. }
  331.  
  332.  
  333. // divide_by_zero -- Raise Error exception for divide by zero
  334. // Input:            Character string of derived class name and function
  335. // Output:           None
  336.  
  337. void CoolRational::divide_by_zero (const char* name) const {
  338.   //RAISE (Error, SYM(CoolRational), SYM(Divide_By_Zero),
  339.   printf ("CoolRational::%s: Divide by zero.\n", name);
  340.   abort ();                    // terminate in error with exit
  341. }
  342.  
  343.  
  344. // print --  terse print function for CoolRational
  345. // Inputs:   reference to output stream
  346. // Outputs:  none
  347.  
  348. void CoolRational::print(ostream& os) {
  349.   os << form("                /* CoolRational %lx */", (long) this);
  350. }
  351.